
package com.shinyray.common.view.bean;


import com.shinyray.common.view.builder.ApplicationBuilder;
import com.shinyray.common.view.util.FacesUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.shinyray.coa.view.jaxb.menu.Node;
import javax.faces.event.ActionEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.util.Collection;
import java.util.Enumeration;
import java.io.Serializable;
import java.util.logging.Logger;

/**
 * <p>Application controller is responsible for managing the presentation
 * layer action and actionListener functionality.  This bean is intended
 * to stay in Application scope and act on request and session beans as
 * needed. This class mainly handles site navigation processing via the tree
 * and common Tabset components.  Source and Document iFrame links are
 * also processed by this class.</p>
 * <p/>
 * <p>Each individual component showcase example has its own set of Beans which
 * are issolated from the main application and other examples.  Some examples
 * use a common mock service layer for retrieving Employee Objects.</p>
 *
 * @since 1.7
 */
public class ApplicationController  implements Serializable {


    private Logger logger=Logger.getLogger(ApplicationController.class.getName());

    /**
     * <p>Tree navigation events are processed by this method when a tree
     * leaf or folder is clicked on by the user.  This method assumes
     * that the navigation node in question passed the request param
     * "nodeId" in the request map.  The "nodeId" is a unique id assigned to
     * the node from the application meta data.  This ide is then used
     * to find the corresponding Node object from the ApplicationBuilder class</p>
     * <p/>
     * <p>A node is marked as selected and the previously selected node is
     * marked as unselected.  The nodes corresponding include may have
     * a tabSet state which will either be loaded or initialized.  This is
     * important to note as it allows the use of only one tabSetComponent
     * for the intire application.</p>
     *
     * @param event jsf action event
     */
    public void navigationEvent(ActionEvent event) {

        // get id of node that was clicked on.
        String nodeId = FacesUtils.getRequestParameter("nodeId");

        // get a reference to the application scoped application builder.
        ApplicationBuilder applicationBuilder =
                (ApplicationBuilder) FacesUtils.getManagedBean(
                        BeanNames.APPLICATION_BUILDER);

        // do a bean lookup by node Id
        Node node = applicationBuilder.getNode(nodeId);

        // not all notes are marked as links and some nodes may be null
        // if the meta data was not correctly validated.
        if (node != null && node.isLink()) {

            // get a reference to the sessionModel data
            ApplicationSessionModel applicationModel =
                    (ApplicationSessionModel) FacesUtils.getManagedBean(
                            BeanNames.APPLICATION_MODEL);
            // reset selected state on old selected node.
            setTreeNodeSelectedState(
                    applicationModel.getCurrentNode().getId(), false);

            // set our new current node.
            applicationModel.setCurrentNode(node);

            // mark the new current node as selected
            setTreeNodeSelectedState(
                    applicationModel.getCurrentNode().getId(), true);


        }
        // otherwise we just toggle the expanded state of the node
        // that was selected, should always be a folder
        else if (node != null && !node.isLink()) {
            // toggle expanded state. 
            toggleTreeNodeExpandedState(node.getId());
        }

    }
    public String navigationToView()
    {
        String action="";
        // get id of node that was clicked on.
        String nodeId = FacesUtils.getRequestParameter("nodeId");

        // get a reference to the application scoped application builder.
        ApplicationBuilder applicationBuilder =
                (ApplicationBuilder) FacesUtils.getManagedBean(
                        BeanNames.APPLICATION_BUILDER);

        // do a bean lookup by node Id
        Node node = applicationBuilder.getNode(nodeId);

        // not all notes are marked as links and some nodes may be null
        // if the meta data was not correctly validated.
        if (node != null && node.isLink()) {

            // get a reference to the sessionModel data
            ApplicationSessionModel applicationModel =
                    (ApplicationSessionModel) FacesUtils.getManagedBean(
                            BeanNames.APPLICATION_MODEL);
            // reset selected state on old selected node.
            setTreeNodeSelectedState(
                    applicationModel.getCurrentNode().getId(), false);

            // set our new current node.
            applicationModel.setCurrentNode(node);

            // mark the new current node as selected
            setTreeNodeSelectedState(
                    applicationModel.getCurrentNode().getId(), true);
            action=node.getContentRef();

        }
        // otherwise we just toggle the expanded state of the node
        // that was selected, should always be a folder
        else if (node != null && !node.isLink()) {
            // toggle expanded state.
            toggleTreeNodeExpandedState(node.getId());

        }
        return action;
    }


    /**
     * Utility method to assign the selected state of a tree node.
     *
     * @param nodeId nodeId of the node to set the selected state on.
     * @param value  desired selection state of node.
     */
    private void setTreeNodeSelectedState(String nodeId, boolean value) {
        DefaultMutableTreeNode defaultNode = findTreeNode(nodeId);
        if (defaultNode != null) {
            NavigationTreeNode node =
                    (NavigationTreeNode) defaultNode.getUserObject();
            node.setSelected(value);
        }
    }

    /**
     * Utility method to toggle the selected state of the specified node.
     *
     * @param nodeId nodeId of the the node to toggle the expanded state of.
     */
    private void toggleTreeNodeExpandedState(String nodeId) {
        DefaultMutableTreeNode defaultNode = findTreeNode(nodeId);
        if (defaultNode != null) {
            NavigationTreeNode node = (NavigationTreeNode) defaultNode.getUserObject();
            node.setExpanded(!node.isExpanded());
        }
    }

    /**
     * Utility method to find a tree node by its ID.
     *
     * @param nodeId node Id of node to to find in tree.
     * @return node specified by ID or null of no node of that ID is found.
     */
    private DefaultMutableTreeNode findTreeNode(String nodeId) {
        ApplicationSessionModel applicationModel =
                (ApplicationSessionModel) FacesUtils.getManagedBean(
                        BeanNames.APPLICATION_MODEL);
        Collection<DefaultTreeModel> trees =
                applicationModel.getNavigationTrees().values();

        DefaultMutableTreeNode node;
        DefaultMutableTreeNode rootNode;
        // search all trees defined by meta data using a depthFirst search.
        for (DefaultTreeModel treeModel : trees) {
            rootNode = (DefaultMutableTreeNode) treeModel.getRoot();
            Enumeration nodes = rootNode.depthFirstEnumeration();
            while (nodes.hasMoreElements()) {
                node = (DefaultMutableTreeNode) nodes.nextElement();
                NavigationTreeNode tmp = (NavigationTreeNode) node.getUserObject();
                if (tmp.getNodeId() != null && tmp.getNodeId().equals(nodeId)) {
                    return node;
                }
            }
        }
        return null;
    }

}
